<template>
  <div>
    <a-button type="primary" @click="showModal = true">上传课件</a-button>

    <a-modal
      v-model:open="showModal"
      :width="800"
      title="上传课件"
      ok-text="确认"
      cancel-text="取消"
      :mask-closable="false"
      @ok="closeWin"
      @cancel="closeWin"
    >
      <a-row :gutter="[0,10]">
        <a-col :span="24">
            <a-upload-dragger
                v-bind="uploadProps"
                :file-list="fileList"
            >
                <p class="ant-upload-drag-icon">
                    <InboxOutlined />
                </p>
                <p class="ant-upload-text">请将文件拖拽到此处上传</p>
                <p class="ant-upload-hint">
                  支持一次上传多个 /
                  支持word、excel、ppt、pdf、zip、rar、txt格式文件
                </p>
            </a-upload-dragger>
        </a-col>

        <a-col :span="24">
          <a-table
            :columns="columns"
            :data-source="fileList"
            :pagination="false"
            row-key="id"
          />
        </a-col>
      </a-row>
    </a-modal>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted, watchEffect, h } from "vue";
import {
  message,
  Modal as AModal,
  Button as AButton,
  Row as ARow,
  Col as ACol,
  Table as ATable,
  Progress,
  Tag,
} from "ant-design-vue";
import { InboxOutlined } from "@ant-design/icons-vue";
import { generateUUID } from "@/utils";
import { minioUploadId, minioMergeVideo } from "@/api/upload";
import { UploadChunk } from "@/js/minio-upload-chunk";

interface FileItem {
  id: string;
  file: File;
  upload: {
    handler: UploadChunk;
    progress: number;
    status: number;
    remark: string;
  };
}

const props = defineProps<{
  categoryIds: number[];
  onUpdate: () => void;
}>();

const showModal = ref(false);
const localFileList = ref<FileItem[]>([]);
const fileList = ref<FileItem[]>([]);
let intervalId: number | undefined;

// 表格列
const columns = [
  {
    title: "课件",
    key: "name",
    customRender: ({ record }: any) => record.file.name,
  },
  {
    title: "大小",
    key: "size",
    customRender: ({ record }: any) =>
      (record.file.size / 1024 / 1024).toFixed(2) + "M",
  },
  {
    title: "进度",
    key: "progress",
    customRender: ({ record }: any) => {
      return record.upload.status === 0
        ? "等待上传"
        : h(Progress, { size: "small", steps: 20, percent: record.upload.progress });
    },
  },
  {
    title: "操作",
    key: "action",
    customRender: ({ record }: any) =>
      h("div", [
        record.upload.status === 5
          ? h(Tag, { color: "red" }, () => record.upload.remark)
          : null,
        record.upload.status === 7
          ? h(Tag, { color: "success" }, () => "上传成功")
          : null,
      ]),
  },
];

// 获取 minio uploadId
const getMinioUploadId = async (extension: string) => {
  const resp: any = await minioUploadId(extension);
  return resp.data;
};

// 上传配置
const uploadProps = reactive({
  multiple: true,
  beforeUpload: async (file: File) => {
    if (file.size === 0) {
      message.error(`文件 ${file.name} 为空文件`);
      return false;
    }

    const allowedExts = ["doc","docx","xls","xlsx","ppt","pptx","pdf","zip","rar","txt"];
    const extension = file.name.split(".").pop()?.toLowerCase() || "";

    if (!allowedExts.some(t => file.name.toLowerCase().endsWith(t))) {
      message.error(`${file.name} 并不是可上传文件`);
      return false;
    }

    const data = await getMinioUploadId(extension);
    const handler = new UploadChunk(file, data.upload_id, data.filename);

    const item: FileItem = {
      id: generateUUID(),
      file,
      upload: { handler, progress: 0, status: 0, remark: "" },
    };

    // 监听上传事件
    handler.on("success", () => {
      minioMergeVideo(
        data.filename,
        data.upload_id,
        props.categoryIds.join(","),
        file.name,
        extension,
        file.size,
        0,
        ""
      ).then(() => {
        item.upload.progress = 100;
        item.upload.status = handler.getUploadStatus();
        fileList.value = [...localFileList.value];
      });
    });

    handler.on("progress", (p: number) => {
      item.upload.status = handler.getUploadStatus();
      item.upload.progress = p >= 100 ? 99 : p;
      fileList.value = [...localFileList.value];
    });

    handler.on("error", (msg: string) => {
      item.upload.status = handler.getUploadStatus();
      item.upload.remark = msg;
      fileList.value = [...localFileList.value];
    });

    // 保存到本地待上传列表
    localFileList.value.push(item);
    fileList.value = [...localFileList.value];

    return false; // 阻止 a-upload 默认上传
  },
});

// 定时器触发上传
onMounted(() => {
  watchEffect(() => {
    if (showModal.value) {
        intervalId = window.setInterval(() => {
            for (const f of localFileList.value) {
                if (f.upload.status === 0) {
                f.upload.handler.start();
                }
            }
        }, 1000);
    } else {
      window.clearInterval(intervalId);
    }
  });
});

// 关闭窗口
const closeWin = () => {
  fileList.value.forEach(item => {
    if (item.upload.status !== 5 && item.upload.status !== 7) {
      item.upload.handler.cancel();
    }
  });
  props.onUpdate();
  localFileList.value = [];
  fileList.value = [];
  showModal.value = false;
};
</script>

<style scoped>
.ant-upload-drag-icon {
  font-size: 48px;
  color: #1890ff;
}
.ant-upload-text {
  font-size: 16px;
  color: #000;
}
.ant-upload-hint {
  font-size: 14px;
  color: #666;
}
</style>
